package cn.com.doone.common.uc.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.com.doone.common.uc.domain.oauth.AccessToken;
import cn.com.doone.common.uc.domain.oauth.AuthenticationIdGenerator;
import cn.com.doone.common.uc.domain.oauth.ClientDetails;
import cn.com.doone.common.uc.domain.oauth.OauthCode;
import cn.com.doone.common.uc.domain.oauth.OauthRepository;
import cn.com.doone.common.uc.domain.rs.OAuthRSRepository;
import cn.com.doone.common.uc.infrastructure.ldap.OAuthRSLdapRepository;
import cn.com.doone.common.uc.service.OAuthRSService;
import cn.com.doone.common.uc.utils.PropertiesUtils;
import cn.com.doone.common.uc.utils.StringUtils;

/**
 * 2015/7/8
 *
 * @author Shengzhao Li
 */
@Service("oAuthRSService")
public class OAuthRSServiceImpl implements OAuthRSService {


    private static final Logger LOG = LoggerFactory.getLogger(OAuthRSServiceImpl.class);

    @Autowired
    private OauthRepository oauthRepository;
    
    @Autowired
    private OAuthIssuer oAuthIssuer;
    
    @Autowired
    private OAuthRSRepository oauthRSJdbcRepository;
    
    @Autowired
    private OAuthRSLdapRepository oAuthRSLdapRepository;
    
    @Autowired
    private PropertiesUtils propertiesUtils;
    
    @Autowired
    private AuthenticationIdGenerator authenticationIdGenerator;

    @Override
    public AccessToken loadAccessTokenByTokenId(String tokenId) {
        return oauthRSJdbcRepository.findAccessTokenByTokenId(tokenId);
    }

    @Override
    public ClientDetails loadClientDetails(String clientId, String resourceIds) {
        LOG.debug("Load ClientDetails by clientId: {}, resourceIds: {}", clientId, resourceIds);
        return oauthRSJdbcRepository.findClientDetailsByClientIdAndResourceIds(clientId, resourceIds);
    }
    
    public Map<String, Object> getUserInfo(String username) {
    	Map<String, Object> userMap = oauthRSJdbcRepository.getUserInfo(username);
    	
    	String headPortrait = userMap.get("headPortrait") == null ? "" : (String) userMap.get("headPortrait");
    	
    	if (headPortrait != null && !headPortrait.isEmpty()) {
    		userMap.put("headPortrait", propertiesUtils.getHeadPath() + headPortrait);
    	}
    	//查询对应的岗位和组
    	String userInfoId = userMap.get("userInfoId").toString();
    	List<Map<String,Object>> postTypeList = oauthRSJdbcRepository.getGroupPostTypeListByUserInfoId(userInfoId);
    	userMap.put("postTypeList", postTypeList);
    	
    	List<Map<String, Object>> groupCodeList = oauthRSJdbcRepository.getTenantInfo(username);
    	
    	List<String> ouList = new ArrayList<String>();
    	List<String> shieldList = new ArrayList<String>();
    	
    	Map<String, Object> tenantMap = new HashMap<String, Object>();
    	for (Map<String, Object> groupCodeMap : groupCodeList) {
    		String groupCode = (String) groupCodeMap.get("GROUP_CODE");
    		
    		if (groupCode != null && !groupCode.isEmpty()) {
    			if (tenantMap.get(groupCode.split(":")[0]) == null) {
    				tenantMap.put(groupCode.split(":")[0], groupCode.split(":")[0]);
    				
    				Map<String, Object> codeMap = oauthRSJdbcRepository.getTenantCode(groupCode.split(":")[0]);
    				
    				String tenantCode = (String) codeMap.get("TENANT_CODE");
    				
    				if (tenantCode != null && !tenantCode.isEmpty()) {
    					ouList.add(tenantCode);
    					shieldList.add(StringUtils.isNull(codeMap.get("SHIELD_COLUMN"))?"":codeMap.get("SHIELD_COLUMN").toString());
    				}
    				
    			}
    		}
    		
    	}
    	
    	if (ouList.size() > 0) {
    		userMap.put("dc", ouList.get(0));
    		userMap.put("shield", shieldList);
    		userMap.put("tenantCode", ouList);
    	}
    	
		return userMap;
    }

	@Override
	public void uploadHeadPortrait(String username, String headPortraitName) {
		Map<String, Object> userMap = oauthRSJdbcRepository.getUserInfo(username);
		
		if (userMap.get("dooneCode") == null) {
			userMap.put("dooneCode", (Integer) userMap.get("userInfoId") + 20000);
		}
		
		userMap.put("headPortrait", headPortraitName);

		Map<String, Object> userExtendMap = oauthRSJdbcRepository.getUserInfoExtend((Integer) userMap.get("userInfoId"));

		// 是否已经有扩展信息
		if (userExtendMap != null) {
			oauthRSJdbcRepository.updateUserInfoExtend(userMap);
		} else {
			oauthRSJdbcRepository.saveUserInfoExtend(userMap);
		}
		
	}
	
	/**
	 * 修改个人信息
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public void updateUserInfo(Map map) throws Exception {
		
		oauthRSJdbcRepository.updateUserInfo(map);
		
		// 若配置了LDAP服务器
		if (propertiesUtils.isLdapEnable()) {
			String tenantFullName = "OU=Account,dc=doone,dc=com,dc=cn";
			oAuthRSLdapRepository.updateUserInfo(map, tenantFullName);
		}
		
	}

	/**
	 * 生成一次性信息授权码
	 */
	@Override
	public String genInfoCode(AccessToken accessToken) throws Exception {
		
		String authCode = oAuthIssuer.authorizationCode();
		
		OauthCode oauthCode = new OauthCode()
	        .code(authCode).username(accessToken.username())
	        .clientId(accessToken.clientId());
	
		oauthRepository.saveOauthCode(oauthCode);
		
		return authCode;
	}

	@Override
	public Map<String, Object> getUserInfoByCode(String infoCode, String appCode, String clientId) throws Exception {
		
		OauthCode oauthCode = oauthRepository.findOauthCode(infoCode, clientId);
		
		String username = oauthCode.username();
		
		Map<String, Object> userMap = oauthRepository.findUserInfoByUserAccountSimple(username);
		
		oauthRepository.deleteOauthCode(oauthCode);
		
		return userMap;
	}

	@Override
	public List<Map<String, Object>> findWechatIdList(String clientId, String clientSecret, String appCode) {
		return oauthRepository.findWechatIdList(clientId, appCode);
	}

	@Override
	public Map<String, Object> findWechatIdByUserInfoId(int userInfoId, String appCode) {
		return oauthRepository.findWechatIdByUserInfoId(userInfoId, appCode);
	}

	@Override
	public Map<String, Object> queryInfoByToken(Map<String, Object> paramsMap) {
		return oauthRSJdbcRepository.queryInfoByToken(paramsMap);
	}

	@Override
	public String createCode(Map<String, Object> paramsMap) throws OAuthSystemException {
		String username = paramsMap.get("username").toString();
		String clientId = paramsMap.get("clientId").toString();
		OauthCode oauthCode = oauthRepository.findOauthCodeByUsernameClientId(username, clientId);
		if (oauthCode != null) {
            //Always delete exist
            oauthRepository.deleteOauthCode(oauthCode);
        }
		
    	final String authCode = oAuthIssuer.authorizationCode();
    	oauthCode = new OauthCode().code(authCode).clientId(clientId).username(username);
		
		oauthRepository.saveOauthCode(oauthCode);
		return oauthCode.code();
	}

	@Override
	public Map<String, Object> updateUserExpandInfo(Map<String, Object> paramsMap) {
		Map<String,Object> resultMap = new HashMap<String,Object>();
		Map<String,Object> userInfoMap = oauthRSJdbcRepository.queryInfoByToken(paramsMap);
		if(userInfoMap == null) {
			resultMap.put("success", false);
			resultMap.put("msg", "查无数据");
			return resultMap;
		}
		
		userInfoMap = oauthRSJdbcRepository.getUserInfo(userInfoMap.get("username").toString());
		if(StringUtils.isNull(userInfoMap.get("userInfoId"))) {
			resultMap.put("success", false);
			resultMap.put("msg", "查无数据");
			return resultMap;
		}
		paramsMap.put("userInfoId", userInfoMap.get("userInfoId"));
		oauthRSJdbcRepository.updateUserInfoExtend(paramsMap);
		resultMap.put("success", true);
		resultMap.put("filePath", paramsMap.get("filePath"));
		return resultMap;
	}

	@Override
	public Map<String,Object> createTokenByToken(Map<String,Object> paramsMap) throws Exception {
		Map<String,Object> resultMap = new HashMap<String,Object>();
		//根据token查询username
		Map<String,Object> tokenMap = oauthRSJdbcRepository.queryInfoByToken(paramsMap);
		if(StringUtils.isNull(tokenMap) || tokenMap.isEmpty()) {
			resultMap.put("success", false);
			resultMap.put("message", "查无对应的用户信息");
			return resultMap;
		}
		String username = tokenMap.get("username").toString();
		String clientId = paramsMap.get("app_id").toString();
		Map<String,Object> appInfoMap = oauthRSJdbcRepository.queryAppInfoByClientId(clientId);
		if(StringUtils.isNull(appInfoMap.get("SCOPE"))) {
			resultMap.put("success", false);
			resultMap.put("message", "查无应用信息");
			return resultMap;
		}
		String scope = appInfoMap.get("SCOPE").toString();
		String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);
		AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
		if(accessToken != null) {
			oauthRepository.deleteAccessToken(accessToken);
		}
		accessToken = new AccessToken()
				.clientId(clientId)
				.username(username)
				.tokenId(oAuthIssuer.accessToken())
				.refreshToken(oAuthIssuer.refreshToken())
				.authenticationId(authenticationId);
		oauthRepository.saveAccessToken(accessToken);
		resultMap.put("token", accessToken.tokenId());
		resultMap.put("success", true);
		return resultMap;
	}
	
	@Override
	public Map<String, Object> createTokenByPhone(Map<String, Object> paramsMap) throws OAuthSystemException {
		Map<String,Object> resultMap = new HashMap<String,Object>();
		
		//根据手机号码查询用户
		String mobilePhone = paramsMap.get("mobilePhone").toString();
		Map<String,Object> userInfoMap = oauthRSJdbcRepository.queryUserInfoByPhone(mobilePhone);
		if(StringUtils.isNull(userInfoMap.get("username"))) {
			resultMap.put("success", false);
			resultMap.put("message", "查不到对应的用户");
			return resultMap;
		}
		String username = userInfoMap.get("username").toString();
		String clientId = paramsMap.get("clientId").toString();
		//根据clientId查询应用信息
		Map<String,Object> appInfoMap = oauthRSJdbcRepository.queryAppInfoByClientId(clientId);
		if(StringUtils.isNull(appInfoMap.get("SCOPE"))) {
			resultMap.put("success", false);
			resultMap.put("message", "查无应用信息");
			return resultMap;
		}
		String scope = appInfoMap.get("SCOPE").toString();
		String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);
		AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
		if(accessToken != null) {
			oauthRepository.deleteAccessToken(accessToken);
		}
		accessToken = new AccessToken()
				.clientId(clientId)
				.username(username)
				.tokenId(oAuthIssuer.accessToken())
				.refreshToken(oAuthIssuer.refreshToken())
				.authenticationId(authenticationId);
		oauthRepository.saveAccessToken(accessToken);
		resultMap.put("token", accessToken.tokenId());
		resultMap.put("success", true);
		return resultMap;
	}

	@Override
	public Map<String, Object> createTokenByAccount(Map<String, Object> paramsMap) throws OAuthSystemException {
		Map<String,Object> resultMap = new HashMap<String,Object>();
		String username = paramsMap.get("userAccount").toString();
		String clientId = paramsMap.get("clientId").toString();
		//根据clientId查询应用信息
		Map<String,Object> appInfoMap = oauthRSJdbcRepository.queryAppInfoByClientId(clientId);
		if(StringUtils.isNull(appInfoMap.get("SCOPE"))) {
			resultMap.put("success", false);
			resultMap.put("message", "查无应用信息");
			return resultMap;
		}
		String scope = appInfoMap.get("SCOPE").toString();
		String authenticationId = authenticationIdGenerator.generate(clientId, username, scope);
		AccessToken accessToken = oauthRepository.findAccessToken(clientId, username, authenticationId);
		if(accessToken != null) {
			oauthRepository.deleteAccessToken(accessToken);
		}
		accessToken = new AccessToken()
				.clientId(clientId)
				.username(username)
				.tokenId(oAuthIssuer.accessToken())
				.refreshToken(oAuthIssuer.refreshToken())
				.authenticationId(authenticationId);
		oauthRepository.saveAccessToken(accessToken);
		resultMap.put("access_token", accessToken.tokenId());
		resultMap.put("token_type", accessToken.tokenType());
		resultMap.put("expires_in", accessToken.tokenExpiredSeconds());
		resultMap.put("refresh_token", accessToken.refreshToken());
		resultMap.put("success", true);
		return resultMap;
	}
}
